<?php
declare(strict_types=1);

namespace Zlf\Sms;

use Zlf\AppException\Exception\AppException;
use Zlf\Sms\Drive\Alsms;
use Zlf\Sms\Drive\Fxsms;
use Zlf\Sms\Drive\SmsBasics;
use Zlf\Sms\Drive\Ztsms;

/**
 * 短信发送类
 * 提供了短信驱动的实例化、驱动名称获取以及驱动验证的功能。
 */
class Sms
{
    /**
     * 存储短信实例
     * @var array
     */
    private $_instance;//短信实例

    /**
     * 获取短信实例
     * 根据提供的驱动程序名称和配置回调函数创建并返回一个短信实例。
     *
     * @param string $drive 短信驱动程序名称，例如 Alsms::class, Ztsms::class 等
     * @param callable $callable 配置获取回调函数，用于设置短信实例的配置
     * @return SmsBasics 返回一个短信基础实例
     * @throws AppException 如果提供的驱动程序名称无效，则抛出异常
     */
    public function instance(string $drive, callable $callable): SmsBasics
    {
        $this->checkDrive($drive);
        if (!(isset($this->_instance[$drive]) && $this->_instance[$drive] instanceof SmsBasics)) {
            /**
             * @var SmsBasics $driveInstance
             */
            $driveInstance = new $drive;
            $driveInstance->setConfigCallable($callable);
            $this->_instance[$drive] = $driveInstance;
        }
        return $this->_instance[$drive];
    }

    /**
     * 获取所有可用短信驱动程序列表
     * 返回一个包含所有可用短信驱动及其描述的数组。
     *
     * @return array 包含驱动名称和描述的数组
     */
    public static function drives(): array
    {
        return [
            ['drive' => Alsms::class, 'desc' => '阿里云短信'],
            ['drive' => Ztsms::class, 'desc' => '助通科技短信'],
            ['drive' => Fxsms::class, 'desc' => '分享短信']
        ];
    }

    /**
     * 获取驱动名称
     * 根据提供的驱动程序名称返回对应的描述信息。
     *
     * @param string $drive 驱动程序名称
     * @return string 驱动程序描述信息
     */
    public static function getDriveName(string $drive): string
    {
        foreach (self::drives() as $item) {
            if ($item['drive'] === $drive) {
                return $item['desc'];
            }
        }
        return '';
    }

    /**
     * 检查短信驱动
     * 验证提供的驱动程序名称是否有效。如果无效则抛出异常。
     *
     * @param string $drive 驱动程序名称
     * @return void
     * @throws AppException 如果提供的驱动程序名称不在支持的驱动列表中，则抛出异常
     */
    private function checkDrive(string $drive)
    {
        foreach (self::drives() as $item) {
            if ($item['drive'] === $drive) {
                return;
            }
        }
        throw new AppException("短信驱动错误");
    }
}